Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /** * Normalize redirect paths collected from query params or middleware. * Ensures we never navigate to Next.js RSC payloads (e.g., "/admin.txt") * or allow absolute URLs that could trigger open redirects. */ export function sanitizeRedirectPath(input?: string | null): string | undefined { if (!input) return undefined; const trimmed = input.trim(); if (!trimmed) return undefined; // Disallow absolute URLs to avoid open-redirect issues if (/^https?:\/\//i.test(trimmed)) { try { const url = new URL(trimmed); return sanitizeRedirectPath(`${url.pathname}${url.search}${url.hash}`); } catch { return undefined; } } // Ensure we operate on a leading slash path for URL parsing const normalized = trimmed.startsWith('/') ? trimmed : `/${trimmed}`; try { const url = new URL(normalized, 'http://localhost'); let pathname = url.pathname.replace(/\/{2}/g, '/'); // Strip trailing "index" segments to keep canonical routes ("/admin/index" -> "/admin") if (pathname.endsWith('/index')) { pathname = pathname.slice(0, -6) || '/'; } // Remove RSC/Text payload suffixes such as ".txt" if (pathname.endsWith('.txt')) { pathname = pathname.slice(0, -4) || '/'; } if (!pathname.startsWith('/')) { pathname = `/${pathname}`; } const sanitized = `${pathname}${url.search}${url.hash}`; return sanitized || undefined; } catch { return undefined; } } |